package Math
{
	/**
	 * @author Perry
	 */
	public class Quaternion
	{
		private var x0:Number;
		private var x1:Number;
		private var x2:Number;
		private var x3:Number;

		public function Quaternion( x0In:Number, x1In:Number, x2In:Number, x3In:Number )
		{
			x0 = x0In;
			x1 = x1In;
			x2 = x2In;
			x3 = x3In;
		}
		
		public function toString():String
		{
			return x0 + " + " + x1 + "i " + x2 + "j " + x3 + "k";
		}
		
		public function norm():Number
		{
			return Math.sqrt( x0 * x0 + x1 * x1 + x2 * x2 + x3 * x3 );
		}
		
		public function conjugate():Quaternion
		{
			return new Quaternion( x0, -x1, -x2, -x3 );
		}
		
		public function plus( b:Quaternion ):Quaternion
		{
			var a:Quaternion = this;
			
			return new Quaternion( a.x0 + b.x0, a.x1 + b.x1, a.x2 + b.x2, a.x3 + b.x3 );
		}
		
		public function times( b:Quaternion ):Quaternion
		{
			var a:Quaternion = this;
			
			var y0:Number = a.x0 * b.x0 - a.x1 * b.x1 - a.x2 * b.x2 - a.x3 * b.x3;
			var y1:Number = a.x0 * b.x1 + a.x1 * b.x0 + a.x2 * b.x3 - a.x3 * b.x2;
			var y2:Number = a.x0 * b.x2 - a.x1 * b.x3 + a.x2 * b.x0 + a.x3 * b.x1;
			var y3:Number = a.x0 * b.x3 + a.x1 * b.x2 - a.x2 * b.x1 + a.x3 * b.x0;
			
			return new Quaternion( y0, y1, y2, y3 );
		}
		
		public function inverse():Quaternion
		{
			var d:Number = x0 * x0 + x1 * x1 + x2 * x2 + x3 * x3;
			
			return new Quaternion( x0 / d, -x1 / d, -x2 / d, -x2 / d );
		}
		
		public function divides( b:Quaternion ):Quaternion
		{
			var a:Quaternion = this;
			
			return a.inverse().times( b );
		}

	}
}
